import axios from 'axios'
import type { AxiosInstance } from 'axios' // axios实例类型
import router from '@/router'
import { RequestConfig, RequestInterceptors } from './type' // axios参数类型

import { Toast } from 'vant'
import { removeItem } from '@/utils/storage'
// Toast.allowMultiple() // 关闭单例模式
const DEFAUL_LOADING = true
const SUCCESS_LOADING = true
class Request {
  // axios实例
  instance: AxiosInstance
  // 单个实例拦截器
  interceptors?: RequestInterceptors
  // loading显示隐藏
  showLoading: boolean
  // loading
  loading?: any
  // 成功loading
  showSuccess: boolean

  constructor(config: RequestConfig) {
    this.instance = axios.create(config)
    this.interceptors = config.interceptors
    this.showLoading = config.showLoading ?? DEFAUL_LOADING
    this.showSuccess = config.showSuccess ?? SUCCESS_LOADING
    // 单个实例请求拦截器
    this.instance.interceptors.request.use(
      this.interceptors?.requestInterceptor,
      this.interceptors?.requestInterceptorCatch
    )
    // 单个实例响应拦截器
    // this.instance.interceptors.response.use(
    //   this.interceptors?.respenseInterceptor,
    //   this.interceptors?.respenseInterceptorCatch
    // )
    // 请求拦截器
    this.instance.interceptors.request.use(
      (config) => {
        // 加载loading
        if (this.showLoading) {
          this.loading = Toast.loading({
            message: '加载中...',
            forbidClick: true,
            loadingType: 'spinner',
            duration: 0
          })
        }
        return config
      },
      (error) => {
        return error
      }
    )

    // 响应拦截器
    this.instance.interceptors.response.use(
      (res) => {
        if (this.showLoading) {
          this.loading.clear()
        }
        const data = res.data
        if (data.code !== '0') {
          Toast.fail(data.msg)
        }
        if (this.showSuccess && data.code === '0') {
          Toast.success({
            message: data.msg,
            duration: 500
          })
        }
        return data
      },
      (error) => {
        if (this.showLoading) {
          this.loading.clear()
        }
        // 公共错误处理
        if (error && error.response) {
          switch (error.response.status) {
            case 400:
              Toast.fail('错误请求')
              break
            case 401:
              removeItem('token')
              router.push('/login')
              Toast.fail('未授权，请重新登录')
              break
            case 403:
              Toast.fail('拒绝访问')
              break
            case 404:
              Toast.fail('请求错误,未找到该资源')
              break
            case 405:
              Toast.fail('请求方法未允许')
              break
            case 408:
              Toast.fail('请求超时')
              break
            case 500:
              Toast.fail('服务器端出错')
              break
            case 501:
              Toast.fail('网络未实现')
              break
            case 502:
              Toast.fail('网络错误')
              break
            case 503:
              Toast.fail('服务不可用')
              break
            case 504:
              Toast.fail('网络超时')
              break
            case 505:
              Toast.fail('http版本不支持该请求')
              break
            default:
              Toast.fail(`连接错误${error.response.status}`)
          }
        } else {
          // 超时处理
          Toast.fail('服务器响应超时,请刷新当前页')
        }
        return error
      }
    )
  }

  // 请求
  request<T = any>(config: RequestConfig<T>): Promise<T> {
    return new Promise((resolve, reject) => {
      // 单个实例请求拦截器执行
      if (config.interceptors?.requestInterceptor) {
        config = config.interceptors.requestInterceptor(config)
      }
      // 判断是否要设置loading
      if (config.showLoading === false) {
        this.showLoading = false
      }
      if (config.showSuccess === false) {
        this.showSuccess = false
      }
      this.instance
        .request<any, T>(config)
        .then((res) => {
          // 单个实例响应拦截器执行
          if (config.interceptors?.respenseInterceptor) {
            res = config.interceptors.respenseInterceptor(res)
          }
          // 重置loading状态
          this.showLoading = DEFAUL_LOADING
          this.showSuccess = SUCCESS_LOADING
          resolve(res)
        })
        .catch((err) => {
          // 重置loading状态
          this.showLoading = DEFAUL_LOADING
          this.showSuccess = SUCCESS_LOADING
          reject(err)
          return err
        })
    })
  }
  // 方法
  get<T = any>(config: RequestConfig<T>): Promise<T> {
    return this.request({
      method: 'GET',
      ...config
    })
  }
  post<T = any>(config: RequestConfig<T>): Promise<T> {
    return this.request({
      method: 'POST',
      ...config
    })
  }
  postForm<T = any>(config: RequestConfig<T>): Promise<T> {
    config.headers = {
      'content-type': 'application/x-www-form-urlencoded'
    }
    return this.request({
      method: 'POST',
      ...config
    })
  }
  delete<T = any>(config: RequestConfig<T>): Promise<T> {
    return this.request({
      method: 'DELETE',
      ...config
    })
  }
  patch<T = any>(config: RequestConfig<T>): Promise<T> {
    return this.request({
      method: 'PATCH',
      ...config
    })
  }
}
export default Request
